<template>
  <div style="display: flex; justify-content: center">
    <!-- <el-upload
      v-model:file-list="fileList"
      class="upload-demo"
      multiple
      :on-preview="handlePreview"
      :on-remove="handleRemove"
      :limit="3"
      :on-exceed="handleExceed"
      :before-upload="beforeUpload"
      :http-request="httpRequest"
    >
      <el-button type="primary">点击上传</el-button>
      <template #tip>
        <div class="el-upload__tip">
          png files with a size less than {{ size }}MB.
        </div>
      </template>
    </el-upload> -->

    <!--切片上传-->
    <el-upload
      v-model:file-list="fileList"
      class="upload-demo"
      multiple
      :on-preview="handlePreview"
      :on-remove="handleRemove"
      :limit="3"
      :on-exceed="handleExceed"
      :before-upload="beforeUpload"
      :http-request="httpRequest1"
    >
      <el-button type="primary">切片上传</el-button>
      <template #tip>
        <div class="el-upload__tip">
          png files with a size less than {{ size }}MB.
        </div>
      </template>
    </el-upload>
  </div>

  <!--文件上传百分比-->
  <el-progress
    v-if="showProgress"
    :percentage="uploadPercentage"
    status="success"
  />

  <!--图片预览-->
  <el-image
    v-if="showPreview"
    style="width: 200px; height: 200px"
    :src="imgUrl"
    :preview-src-list="previewList"
    fit="scale-down"
  />
</template>
<script lang="ts" setup>
import { ref, toRaw } from "vue"
import {
  ElMessage,
  ElMessageBox,
  ProgressProps,
  UploadFile,
  UploadRequestOptions,
} from "element-plus"
import Utils from "../util"
// import { uploadFileApi } from "../request/api"

import axios from "axios"
import type { UploadProps, UploadUserFile } from "element-plus"

import sparkMd5 from "spark-md5"
import { BlockList } from "net"

const accepts = [".png"]
//单位M
const size = 10
// 单位kb
const is10Kb = 20 * 1024
const fileList = ref<UploadUserFile[]>([])
let sliceFiles = ref<BlobFile[]>([])
//进度条
let uploadPercentage = ref<Number>(0)
//控制是否展示进度条
let showProgress = ref<Boolean>(false)
//图片预览地址
let imgUrl = ref<string>("")
//文件预览地址
let previewList = ref<string[]>([])
//是否展示预览
let showPreview = ref<Boolean>(false)

const handleRemove: UploadProps["onRemove"] = (file, uploadFiles) => {
  console.log(file, uploadFiles)
}

const handlePreview: UploadProps["onPreview"] = (uploadFile) => {
  console.log(uploadFile)
}

const handleExceed: UploadProps["onExceed"] = (files, uploadFiles) => {
  ElMessage.warning(
    `The limit is 3, you selected ${files.length} files this time, add up to ${
      files.length + uploadFiles.length
    } totally`
  )
}

//上传前钩子，返回Promise，解决校验失败文件依然上传问题
const beforeUpload: UploadProps["beforeUpload"] = (uploadFile) => {
  return new Promise(async (resolve, reject) => {
    //读取文件验证文件后缀，防止通过修改文件名更新文件格式
    const fileBufferPrefix = await Utils.readBuffer(uploadFile, 0, 8)

    const unit8Array = new Uint8Array(fileBufferPrefix)

    const fileSuffix = Utils.getFileSuffix(unit8Array)
    //文件后缀判断
    if (!fileSuffix || !accepts.includes(fileSuffix)) {
      ElMessage(`请选择支持的文件格式${accepts.join("、")}`)
      return reject(false)
    }
    //文件大小判断
    const isLt10M = uploadFile.size / 1024 / 1024 < size
    if (!isLt10M) {
      ElMessage(`请选择小于${size}M的文件进行上传！`)
      return reject(false)
    }

    //判断文件大于10kb，进行切片上传
    console.log(uploadFile.size)
    if (uploadFile.size > is10Kb) {
      // sliceFiles.value
      const fileArr = await sliceFile(uploadFile)
      sliceFiles.value = fileArr
    }
    resolve(true)
  })
}

// //切片上传
const httpRequest1 = async function (options: UploadRequestOptions) {
  let originFileName = options.file.name
  const fileArr = sliceFiles.value
  let filename = ""
  console.log(fileArr)
  fileArr.forEach(async (item: BlobFile, index: number) => {
    const { chunk, fileName } = item
    filename = fileName
    const isExist = await checkUploadedChunks(fileName)
    //文件名

    if (!isExist) {
      // const fileReader = new FileReader()
      // fileReader.readAsArrayBuffer(chunk)
      // fileReader.addEventListener("load", (event) => {
      //   const arrayBuffer = event.target.result
      //   console.log(arrayBuffer)
      const formData = new FormData()
      formData.append("chunk", chunk)
      formData.append("fileName", fileName)
      console.log(chunk)
      axios({
        url: "/api/uploadChunksNew",
        method: "post",
        data: formData,
        headers: {},
      }).then(async (res) => {
        //合并文件
        if (index === fileArr.length - 1 && res.status) {
          await mergeFiles(filename, originFileName)
        }
      })
      // })
    }
  })
}

//文件上传
const httpRequest = function (options: UploadRequestOptions) {
  let formData = new FormData()
  formData.append("uploadFile", options.file)
  console.log(options.file)
  const name = options.file.name
  const suffix = name.split(".")[1]

  const buffer = getBuffer(options.file)
  //读取到文件对象，将文件名替换为hash值的文件名
  const spark = new sparkMd5.ArrayBuffer()
  spark.append(buffer)
  console.log(spark.end())
  const fileName = spark.end()
  formData.append("fileName", `${fileName}.${suffix}`)
  axios({
    url: "/api/upload",
    method: "post",
    data: formData,
    headers: {
      "Content-Type": "multipart/form-data",
    },
    // `onUploadProgress` 允许为上传处理进度事件
    onUploadProgress: function (progressEvent) {
      const { loaded, total = 0 } = progressEvent
      uploadPercentage.value = (loaded / total) * 100
      showProgress.value = true
    },
  }).then(async (res) => {
    const { data } = res
    if (data.status) {
      ElMessage(`${data.message}`)
      showProgress.value = false
      uploadPercentage.value = 0
      //根据文件内容坐处理预览
      // const imageUrl = await previewImage(options.file)
      // imgUrl.value = imageUrl
      //用后端返回得url坐预览
      imgUrl.value = data.result.file as string
      previewList.value = [imgUrl.value]
      showPreview.value = true
    }
  })
}

interface BlobFile {
  chunk: Blob
  fileName: string
}

//文件切片
const sliceFile = async function (uploadFile: File): Promise<BlobFile[]> {
  const { hash } = await getFileNameHash(uploadFile)
  let fileArr = []
  const chunkSum = Math.ceil(uploadFile.size / is10Kb)
  const chunkSize = Math.ceil(uploadFile.size / chunkSum)
  // let i = 0
  let start = 0
  for (let i = 0; i < chunkSum; i++) {
    let end = start + chunkSize
    if (i == chunkSum - 1) {
      end = start + chunkSize - 1
    }

    fileArr.push({
      chunk: uploadFile.slice(start, end),
      fileName: `${hash}-${i + 1}`,
    })

    start = end
  }

  // while (true) {
  //   let end = start + is10Kb
  //   const blob = uploadFile.slice(start, end + 1)

  //   // const buffer = getBuffer(blob)
  //   // const spark = new sparkMd5.ArrayBuffer()
  //   // spark.append(buffer)
  //   // console.log(spark.end())
  //   // const fileName = spark.end()
  //   if (blob.size === 0) break
  //   console.log(start, end)
  //   if (blob.size) {
  //     fileArr.push({ chunk: blob, fileName: `${hash}-${i + 1}` })
  //     i++
  //     start = end
  //   }
  // }

  return fileArr
}

//文件预览
function previewImage(file: File): Promise<string> {
  return new Promise((resolve) => {
    let fileReader = new FileReader()
    fileReader.readAsDataURL(file)
    fileReader.onload = (ev) => {
      resolve(ev.target!.result as string)
    }
  })
}

//生成buffer
function getBuffer(file: Blob): Promise<Buffer> {
  return new Promise((resolve) => {
    const fileReader = new FileReader()
    fileReader.readAsArrayBuffer(file)
    fileReader.onload = (ev) => {
      resolve(ev.target!.result as Buffer)
    }
  })
}

interface FileNameHash {
  hash: string
}

//生成文件名hash
function getFileNameHash(file: File): Promise<FileNameHash> {
  return new Promise((resolve) => {
    const buffer = getBuffer(file)
    //读取到文件对象，将文件名替换为hash值的文件名
    const spark = new sparkMd5.ArrayBuffer()
    spark.append(buffer)
    console.log(spark.end())
    const fileName = spark.end()
    resolve({ hash: fileName })
  })
}

//合并文件
function mergeFiles(fileName: string, originFileName: string): Promise<string> {
  return new Promise((resolve) => {
    axios({
      url: "/api/mergeFilesN",
      method: "post",
      data: {
        fileName: fileName,
        originFileName,
      },
      headers: {},
    }).then((res) => {
      resolve(res.data.message)
    })
  })
}

//获取唯一文件名
function getIdentifierFileName(file: File): Promise<string> {
  return new Promise((resolve) => {
    const buffer = getBuffer(file)
    //读取到文件对象，将文件名替换为hash值的文件名
    const spark = new sparkMd5.ArrayBuffer()
    spark.append(buffer)
    const fileName = spark.end()
    resolve(fileName)
  })
}
//断点续传
function checkUploadedChunks(chunkName: string): Promise<boolean> {
  return new Promise((resolve) => {
    axios({
      url: "/api/checkUploaded",
      method: "post",
      data: {
        chunkName,
      },
    }).then((res) => {
      if (res.data.status) {
        resolve(res.data.result as boolean)
      }
    })
  })
}
</script>
